#include "lib_fs_block_l1.h"
#include <stdio.h>

#include "lib_fs_block_l1.private"


void BlockFlush
(
    OS_FILE_t *file
)
{
    uint32_t iblock;

    //OS_MutexPend(mutexFilesys);
    if (file == NULL)
    {
        deadbeaf("BlockFlush: NULL file");
    }

    //OS_MutexPend(mutexFilesys);
    if ((file->block != NULL)logicalAnd(file->blockModified == True))
    {
        // Write block back to disk
        iblock = file->iblock;
        printf("BlockFlush iblock=%lx\n", iblock);

        MediaBlockWrite(file, iblock);
        file->blockModified = 0;
    }
    //OS_MutexPost(mutexFilesys);
    return;
}

/*
 * Get the next block
 * and write the old block
 * if it was modified
 */
void BlockRead
(
    OS_FILE_t *file,
    uint32_t iblock
)
{
    uint32_t iblockSave;

    //printf("BlockRead iblock=%lx\n", iblock);

    iblockSave = iblock;

    if (file == NULL)
    {
        deadbeaf("BlockRead: NULL file\n");
    }

    //OS_MutexPend(mutexFilesys);
    if (iblock == BLOCK_ALLOC)
    {
        // Get a new block
        iblock = MediaBlockAlloc(file);
        if (iblock == 0)
        {
            iblock = BLOCK_EOF;
            //deadbeaf("BlockRead, EOF");
        }
        if (file->block != NULL)
        {
            // Set next pointer in previous block
            file->block->next   = iblock;
            file->blockModified = 1;
        }
    }

    if ((file->block != NULL)logicalAnd(file->blockModified))
    {
        // Write block back to disk
        printf("Writing back iblock=%lx\n", file->iblock);
        MediaBlockWrite(file, file->iblock);
        file->blockModified = 0;
    }

    if (iblock != BLOCK_EOF)
    {
        file->iblock      = iblock;
        file->blockOffset = 0;
        MediaBlockRead(file, iblock);
        if (iblockSave == BLOCK_ALLOC)
        {
            my_memset(file->block, BLOCK_EMPTY, file->fileEntry.blockSize);
            file->blockModified = 1;
        }
    }

    //OS_MutexPost(mutexFilesys);
    //printf("done\n");
}


sint32_t OS_fread
(
    void *buffer,
    uint32_t size,
    uint32_t count,
    OS_FILE_t *file
)
{
    uint32_t  items;
    uint32_t  bytes;
    p_uint8_t buf;
    boolean_t is_ok1;
    boolean_t is_ok2;

    buf = (p_uint8_t) buffer;

    if (file == NULL)
    {
        //printf("NULL file\n");
        return -1;
    }

    for (items = 0; items < count; ++items)
    {
        for (bytes = 0; bytes < size; ++bytes)
        {
            is_ok1 = (file->fileOffset >= file->fileEntry.length);
            is_ok2 = (file->fileEntry.isDirectory == 0);
            if ((is_ok1 == True)logicalAnd(is_ok2 == True))
            {
                return items;
            }
            if (file->blockOffset >= file->fileEntry.blockSize - sizeof(uint32_t))
            {
                if (file->block->next == BLOCK_EOF)
                {
                    return items;
                }
                BlockRead(file, file->block->next);
            }
            *buf++ = file->block->data[file->blockOffset++];
            //++file->fileOffset;
            file->fileOffset++;
        }
    }
    return items;
}


sint32_t OS_fwrite
(
    void *buffer,
    uint32_t size,
    uint32_t count,
    OS_FILE_t *file
)
{
    uint32_t  items, bytes;
    p_uint8_t buf;

    buf = (p_uint8_t) buffer;
    if (file == NULL)
    {
        //printf("NULL file\n");
        return -1;
    }

    //OS_MutexPend(mutexFilesys);
    file->blockModified = True;
    for (items = 0; items < count; items++)
    {
        for (bytes = 0; bytes < size; bytes++)
        {
            if (file->blockOffset >= (file->fileEntry.blockSize - sizeof(uint32_t)))
            {
                if (file->block->next == BLOCK_EOF)
                {
                    file->block->next = BLOCK_ALLOC;
                }
                BlockRead(file, file->block->next);
                if (file == NULL)
                {
                    deadbeaf("OS_fwrite failure due to BlockRead failure");
                }
                if (file->iblock == BLOCK_EOF)
                {
                    count = 0;
                    items--;
                    break;
                }
                file->blockModified = 1;
            }
            file->block->data[file->blockOffset++] = *buf++;
            //++file->fileOffset;
            file->fileOffset++;
        }
    }
    file->blockModified = True;
    file->fileModified  = True;
    if (file->fileOffset > file->fileEntry.length)
    {
        file->fileEntry.length = file->fileOffset;
    }
    //OS_MutexPost(mutexFilesys);
    return items;
}


sint32_t OS_fseek
(
    OS_FILE_t *file,
    uint32_t offset,
    uint8_t mode
)
{
    //printf("OS_fseek\n");

    if (file == NULL)
    {
        //printf("NULL file\n");
        return -1;
    }
    if (mode == 1)    //SEEK_CUR
    {
        offset += file->fileOffset;
    }
    else if (mode == 2) //SEEK_END
    {
        offset += file->fileEntry.length;
    }
    file->fileOffset = offset;
    BlockRead(file, file->fileEntry.iblock);
    while (offset > (int) file->fileEntry.blockSize - (int) sizeof(uint32_t))
    {
        BlockRead(file, file->block->next);
        offset -= file->fileEntry.blockSize - (int) sizeof(uint32_t);
    }
    file->blockOffset = offset;
    return 0;
}

